package com.iyoyi.skinlib;

import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
import androidx.appcompat.widget.AppCompatButton;
import androidx.appcompat.widget.AppCompatCheckBox;
import androidx.appcompat.widget.AppCompatCheckedTextView;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.appcompat.widget.AppCompatImageButton;
import androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView;
import androidx.appcompat.widget.AppCompatRadioButton;
import androidx.appcompat.widget.AppCompatRatingBar;
import androidx.appcompat.widget.AppCompatSeekBar;
import androidx.appcompat.widget.AppCompatSpinner;
import androidx.appcompat.widget.AppCompatToggleButton;

import com.iyoyi.skinlib.widget.ImageViewFactory;
import com.iyoyi.skinlib.widget.TextViewFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SkinLayoutFactory implements LayoutInflater.Factory2 {
    private final AppCompatActivity mActivity;
    private final LayoutInflater.Factory2 mBaseFactory;
    private final List<View> mViewList = new ArrayList<>();
    private final Map<View, Map<String, Integer>> mAttributeTable = new HashMap<>();

    SkinLayoutFactory(AppCompatActivity activity, LayoutInflater.Factory2 factory2) {
        mActivity = activity;
        mBaseFactory = factory2;
    }

    @Nullable
    @Override
    public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
        View view = createView(name, context, attrs);
        if (view == null) {
            view = mBaseFactory.onCreateView(parent, name, context, attrs);
        }

        if (view != null) {
            mViewList.add(view);
            createAttrTable(view, attrs);
        }

        return view;
    }


    @Nullable
    @Override
    public View onCreateView(@NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
        View view = createView(name, context, attrs);
        if (view == null) {
            view = mBaseFactory.onCreateView(name, context, attrs);
        }

        if (view != null) {
            mViewList.add(view);
            createAttrTable(view, attrs);
        }

        return view;
    }

    private View createView(@NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
        int idx = name.lastIndexOf('.');
        if (-1 != idx) {
            name = name.substring(idx + 1);
        }

        View view;
        switch (name) {
            case "TextView":
            case "AppCompatTextView":
                view = TextViewFactory.createTextView(context, attrs);
                break;
            case "ImageView":
                view = ImageViewFactory.createImageView(context, attrs);
                break;
            case "Button":
                view = createButton(context, attrs);
                break;
            case "EditText":
                view = createEditText(context, attrs);
                break;
            case "Spinner":
                view = createSpinner(context, attrs);
                break;
            case "ImageButton":
                view = createImageButton(context, attrs);
                break;
            case "CheckBox":
                view = createCheckBox(context, attrs);
                break;
            case "RadioButton":
                view = createRadioButton(context, attrs);
                break;
            case "CheckedTextView":
                view = createCheckedTextView(context, attrs);
                break;
            case "AutoCompleteTextView":
                view = createAutoCompleteTextView(context, attrs);
                break;
            case "MultiAutoCompleteTextView":
                view = createMultiAutoCompleteTextView(context, attrs);
                break;
            case "RatingBar":
                view = createRatingBar(context, attrs);
                break;
            case "SeekBar":
                view = createSeekBar(context, attrs);
                break;
            case "ToggleButton":
                view = createToggleButton(context, attrs);
                break;
            default:
                // The fallback that allows extending class to take over view inflation
                // for other tags. Note that we don't check that the result is not-null.
                // That allows the custom inflater path to fall back on the default one
                // later in this method.
                view = createView(context, name, attrs);
        }
        return view;
    }

    @NonNull
    private AppCompatButton createButton(Context context, AttributeSet attrs) {
        return new AppCompatButton(context, attrs);
    }

    @NonNull
    private AppCompatEditText createEditText(Context context, AttributeSet attrs) {
        return new AppCompatEditText(context, attrs);
    }

    @NonNull
    private AppCompatSpinner createSpinner(Context context, AttributeSet attrs) {
        return new AppCompatSpinner(context, attrs);
    }

    @NonNull
    private AppCompatImageButton createImageButton(Context context, AttributeSet attrs) {
        return new AppCompatImageButton(context, attrs);
    }

    @NonNull
    private AppCompatCheckBox createCheckBox(Context context, AttributeSet attrs) {
        return new AppCompatCheckBox(context, attrs);
    }

    @NonNull
    private AppCompatRadioButton createRadioButton(Context context, AttributeSet attrs) {
        return new AppCompatRadioButton(context, attrs);
    }

    @NonNull
    private AppCompatCheckedTextView createCheckedTextView(Context context, AttributeSet attrs) {
        return new AppCompatCheckedTextView(context, attrs);
    }

    @NonNull
    private AppCompatAutoCompleteTextView createAutoCompleteTextView(Context context,
                                                                     AttributeSet attrs) {
        return new AppCompatAutoCompleteTextView(context, attrs);
    }

    @NonNull
    private AppCompatMultiAutoCompleteTextView createMultiAutoCompleteTextView(Context context,
                                                                               AttributeSet attrs) {
        return new AppCompatMultiAutoCompleteTextView(context, attrs);
    }

    @NonNull
    private AppCompatRatingBar createRatingBar(Context context, AttributeSet attrs) {
        return new AppCompatRatingBar(context, attrs);
    }

    @NonNull
    private AppCompatSeekBar createSeekBar(Context context, AttributeSet attrs) {
        return new AppCompatSeekBar(context, attrs);
    }

    @NonNull
    private AppCompatToggleButton createToggleButton(Context context, AttributeSet attrs) {
        return new AppCompatToggleButton(context, attrs);
    }

    @Nullable
    private View createView(Context context, String name, AttributeSet attrs) {
        return null;
    }

    private void createAttrTable(View view, AttributeSet attrs) {
        Map<String, Integer> map = new HashMap<>();
        for (int i = 0; i < attrs.getAttributeCount(); i += 1) {
            int id = attrs.getAttributeResourceValue(i, View.NO_ID);
            String name = attrs.getAttributeName(i);
            if (id != View.NO_ID) {
                map.put(name, id);
            }
            Log.e("View", view.getClass().getName() + "[name: " + name + ", id: " + id + "]");
        }
        mAttributeTable.put(view, map);
    }

    void destroy() {
        mViewList.clear();
    }

    static void forceSetFactory2(LayoutInflater inflater, LayoutInflater.Factory2 factory) {
        Field sLayoutInflaterFactory2Field;
        try {
            sLayoutInflaterFactory2Field = LayoutInflater.class.getDeclaredField("mFactory2");
            sLayoutInflaterFactory2Field.setAccessible(true);
            sLayoutInflaterFactory2Field.set(inflater, factory);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void update(Resources resources) {
        if (mActivity instanceof OnSkinChangedListener) {
            ((OnSkinChangedListener) mActivity).onSkinChanged(resources);
        }

        for (View view : mViewList) {
            Map<String, Integer> attributeTable = mAttributeTable.get(view);
            if (attributeTable == null) continue;

            switch (view.getClass().getSimpleName()) {
                case "AppCompatTextView":
                    TextViewFactory.get().update(view, resources, attributeTable);
                    break;

                case "AppCompatImageView":
                    ImageViewFactory.get().update(view, resources, attributeTable);
                    break;
            }
        }
    }
}
